﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;

namespace WebAssertTestLibrary.Core
{
    public class XhtmlValidator : W3CValidator
    {
        public XhtmlValidator()
	    {
            ValidatorUrl = "http://validator.w3.org/check";
        }
        
        static readonly AutoResetEvent HtmlBlocker = new AutoResetEvent(true);
        protected override EventWaitHandle Blocker { get { return HtmlBlocker; } }

        public W3CValidityCheckResult ReturnsValidHtml(string url)
        {
            using (var wc = GetWebClient())
            {
                var html = GetResponseBody(wc, url);
                var result = IsValid(wc, html);
                result.Url = url;
                return result;
            }
        }

        public W3CValidityCheckResult IsValidHtml(string html)
        {
            using (var wc = GetWebClient())
            {
                return IsValid(wc, html);
            }
        }

        protected override NameValueCollection PrepareW3CRequest(string payload)
        {
            var values = new NameValueCollection
                             {
                                 {"fragment", payload},
                                 {"prefill", "0"},
                                 {"group", "0"},
                                 {"doctype", "inline"}
                             };
            return values;
        }

        protected override string SendW3CRequest(WebHeaderCollection w3cResponseHeaders, WebClient wc, string url, NameValueCollection values, EventWaitHandle blocker)
        {
            string result;
            try
            {
                blocker.WaitOne();
                byte[] w3cRawResponse = wc.UploadValues(url, values);
                result = Encoding.UTF8.GetString(w3cRawResponse);
                w3cResponseHeaders.Add(wc.ResponseHeaders);
            }
            catch (WebException we)
            {
                we.Data.Add("url", url);
                throw;
            }
            finally
            {
                ThreadPool.QueueUserWorkItem(ResetW3CBlocker, blocker); // Reset on background thread
            }
            return result;
        }

        /// <summary>
        /// Gets the body of a response from the given URL.
        /// </summary>
        /// <param name="wc">The WebClient instance.</param>
        /// <param name="url">The URL.</param>
        /// <returns>The returned content.</returns>
        static string GetResponseBody(WebClient wc, string url)
        {
            // Pretend to be Firefox 3 so that ASP.NET renders compliant HTML
            wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1 (.NET CLR 3.5.30729)";
            wc.Headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            wc.Headers["Accept-Language"] = "en-au,en-us;q=0.7,en;q=0.3";

            string body;
            using (Stream responseStream = wc.OpenRead(url))
            {
                using (var sr = new StreamReader(responseStream))
                {
                    body = sr.ReadToEnd();
                    sr.Close();
                }
            }

            return body;
        }
    }
}